﻿
using System.Collections.Generic;

using Irony.Compiler;

namespace IronLua.Ast {

	public class FunctionExpression : Expression {

		readonly VariableList parameters = new VariableList ();
		readonly BlockStatement body;

		public VariableList Parameters {
			get { return parameters; }
		}

		public BlockStatement Body {
			get { return body; }
		}

		public override LuaNodeType NodeType {
			get { return LuaNodeType.FunctionExpression; }
		}

		public FunctionExpression (CompilerContext context, NonTerminal nonTerminal, SourceLocation location, AstNodeList childNodes)
			: base (context, nonTerminal, location, childNodes)
		{
			var funcbody = childNodes [1];
			if (funcbody.ChildNodes [0] != null && !(funcbody.ChildNodes [0] is BlockStatement))
				parameters.AddRange (CollectParameters (funcbody));
			body = GetBody (funcbody);
		}

		public FunctionExpression (AstNode funcbody)
			: base (null, funcbody.Element as NonTerminal, funcbody.Location, new AstNodeList ())
		{
			if (funcbody.ChildNodes [0] != null && !(funcbody.ChildNodes [0] is BlockStatement))
				parameters.AddRange (CollectParameters (funcbody));
			body = GetBody (funcbody);
		}

		IEnumerable<VariableExpression> CollectParameters (AstNode funcbody)
		{
			var list = funcbody.ChildNodes [0];
			yield return list.ChildNodes [0].ToExpression ().To<VariableExpression> ();

			if (list.ChildNodes.Count > 1 && list.ChildNodes [1] != null && list.ChildNodes [1].ChildNodes.Count > 0) {
				foreach (var node in list.ChildNodes [1].ChildNodes) {
					yield return node.ChildNodes [0].ToExpression ().To<VariableExpression> ();
				}
			}

			if (list.ChildNodes.Count > 2 && list.ChildNodes [2] != null && list.ChildNodes [2].ChildNodes.Count > 0)
				yield return list.ChildNodes [2].ChildNodes [0].ToExpression ().To<VariableExpression> ();
		}

		BlockStatement GetBody (AstNode funcbody)
		{
			return funcbody.ChildNodes [funcbody.ChildNodes.Count - 2].To<BlockStatement> ();
		}

		public override void Accept (ILuaAstVisitor visitor)
		{
			visitor.VisitFunctionExpression (this);
		}
	}
}
